Skip to content

fix: change BodySerializer from any to unknown for strict TypeScript support#3471

Merged
mrlubos merged 7 commits intomainfrom
copilot/support-strict-unknown-typing
Mar 3, 2026
Merged

fix: change BodySerializer from any to unknown for strict TypeScript support#3471
mrlubos merged 7 commits intomainfrom
copilot/support-strict-unknown-typing

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 26, 2026

  • Change BodySerializer = (body: any) => any to BodySerializer = (body: unknown) => unknown in source bundle files
  • Update concrete serializers (formDataBodySerializer, jsonBodySerializer, urlSearchParamsBodySerializer) to accept unknown parameter in both source files
  • Update test custom client template
  • Update test snapshots and example files
  • Fix typecheck failures:
    • Fix serializedBody: undefined initialization by using undefined as string | undefined so TypeScript doesn't infer undefined literal type
    • Fix assignment opts.serializedBody = opts.bodySerializer(opts.body) as string | undefined to explicitly cast the unknown return type
    • Fix test files using (body: object) parameter type — changed to (body: unknown) to match new BodySerializer signature
    • Update all example and snapshot client.gen.ts files with the same fixes
  • Fix snapshot mismatch for sse-tanstack-react-query snapshot files (added in merge from main):
    • core/bodySerializer.gen.ts — updated from old any type to new unknown type
    • client/client.gen.ts — updated with as string | undefined casts
  • All typecheck passes (28 packages)
  • All 1167 tests pass
Original prompt

This section details on the original issue you should resolve

<issue_title>Generated BodySerializer uses any; please support strict unknown typing (or config option)</issue_title>
<issue_description>### Description

Summary

Generated API client code emits BodySerializer as:

export type BodySerializer = (body: any) => any;

For strict TypeScript setups (noImplicitAny, lint rules disallowing any), this creates policy/type-safety violations in otherwise generated-safe code.

What I expected

A stricter default type for serializer signatures, for example:

export type BodySerializer = (body: unknown) => unknown;

or a generator option to choose strictness (e.g. any vs unknown).

What happens currently

Generated files include any in serializer type aliases, requiring post-processing patches in strict repos.

Minimal repro

  1. Generate a client with the current generator defaults.
  2. Inspect generated serializer files (commonly bodySerializer.gen.ts).
  3. Observe BodySerializer = (body: any) => any.

Why this matters

  • Breaks repos that enforce no-any policies.
  • Forces teams to maintain custom patch scripts after generation.
  • Introduces avoidable friction in CI and code review workflows.

Suggested solutions

  1. Change default emitted type to unknown for request/response serializer boundaries.
  2. Or add a generator flag/config to control serializer strictness.
  3. Document the rationale if any is intentionally required, plus recommended strict-mode workaround.

Environment

  • Tool: @hey-api/openapi-ts
  • Generation mode: Axios + React Query plugins
  • TypeScript strict projects with linting rules disallowing any

If helpful, I can provide a concrete reproducible command/config snippet from a minimal repo.
</issue_description>

Comments on the Issue (you are @copilot in this section)


🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

@bolt-new-by-stackblitz
Copy link
Copy Markdown

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@vercel
Copy link
Copy Markdown

vercel bot commented Feb 26, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hey-api-docs Ready Ready Preview, Comment Mar 3, 2026 1:24am

Request Review

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Feb 26, 2026

🦋 Changeset detected

Latest commit: ad11be2

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@hey-api/openapi-ts Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

…support

Co-authored-by: mrlubos <12529395+mrlubos@users.noreply.github.com>
…ple files

Co-authored-by: mrlubos <12529395+mrlubos@users.noreply.github.com>
Copilot AI changed the title [WIP] Update BodySerializer to support strict unknown typing fix: change BodySerializer from any to unknown for strict TypeScript support Feb 26, 2026
@mrlubos
Copy link
Copy Markdown
Member

mrlubos commented Feb 27, 2026

@copilot CI fails on typecheck, please fix. I also think instead of replacing this:

bodySerializer: <T extends Record<string, any> | Array<Record<string, any>>>(
    body: T,
  ): FormData => {

with this:

bodySerializer: (body: unknown): FormData => {

you should've done just this:

bodySerializer: <T extends Record<string, unknown> | Array<Record<string, unknown>>>(
    body: T,
  ): FormData => {

Co-authored-by: mrlubos <12529395+mrlubos@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Feb 27, 2026

@copilot CI fails on typecheck, please fix. I also think instead of replacing this:

bodySerializer: <T extends Record<string, any> | Array<Record<string, any>>>(

...

Fixed in commit 7e85cb0. Two separate typecheck issues were addressed:

  1. serializedBody assignment — The opts object literal { serializedBody: undefined, ... } caused TypeScript to infer a literal undefined type for opts.serializedBody. When bodySerializer now returns unknown, assignment failed. Fixed by:

    • Changing the initialization to serializedBody: undefined as string | undefined in all 5 source bundle client.ts files
    • Casting the assignment: opts.bodySerializer(opts.body) as string | undefined
  2. Test files with (body: object) parameter — Changed to (body: unknown) in 4 test files (client-fetch, client-ky, client-next, client-ofetch) so they're assignable to the updated BodySerializer signature.

@mrlubos
Copy link
Copy Markdown
Member

mrlubos commented Feb 27, 2026

@copilot tests fail, you probably need to run pnpm test:update and pnpm examples:generate

Co-authored-by: mrlubos <12529395+mrlubos@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Feb 27, 2026

@copilot tests fail, you probably need to run pnpm test:update and pnpm examples:generate

Fixed in commit 21d860a. The sse-tanstack-react-query snapshot directory (added in the merge from main) had stale snapshot files with the old types. Ran vitest run --update to regenerate them — 2 files updated: core/bodySerializer.gen.ts (updated BodySerializer type and serializer signatures) and client/client.gen.ts (updated serializedBody casts). All 1167 tests now pass.

@codecov
Copy link
Copy Markdown

codecov bot commented Feb 27, 2026

Codecov Report

❌ Patch coverage is 0% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 40.30%. Comparing base (12c76b8) to head (ad11be2).
⚠️ Report is 22 commits behind head on main.

Files with missing lines Patch % Lines
packages/custom-client/src/core/bodySerializer.ts 0.00% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3471      +/-   ##
==========================================
+ Coverage   40.15%   40.30%   +0.15%     
==========================================
  Files         478      483       +5     
  Lines       17496    17567      +71     
  Branches     5306     5322      +16     
==========================================
+ Hits         7025     7080      +55     
- Misses       8421     8431      +10     
- Partials     2050     2056       +6     
Flag Coverage Δ
unittests 40.30% <0.00%> (+0.15%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Feb 27, 2026

Open in StackBlitz

@hey-api/codegen-core

npm i https://pkg.pr.new/@hey-api/codegen-core@3471

@hey-api/json-schema-ref-parser

npm i https://pkg.pr.new/@hey-api/json-schema-ref-parser@3471

@hey-api/nuxt

npm i https://pkg.pr.new/@hey-api/nuxt@3471

@hey-api/openapi-ts

npm i https://pkg.pr.new/@hey-api/openapi-ts@3471

@hey-api/shared

npm i https://pkg.pr.new/@hey-api/shared@3471

@hey-api/types

npm i https://pkg.pr.new/@hey-api/types@3471

@hey-api/vite-plugin

npm i https://pkg.pr.new/@hey-api/vite-plugin@3471

commit: 68b104d

@mrlubos mrlubos marked this pull request as ready for review March 3, 2026 01:48
@pullfrog
Copy link
Copy Markdown

pullfrog bot commented Mar 3, 2026

Error

agent completed without reporting progress

Pullfrog  | Rerun failed job ➔View workflow run | Triggered by Pullfrogpullfrog.com𝕏

@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Mar 3, 2026
@mrlubos mrlubos merged commit f11f0ae into main Mar 3, 2026
11 of 17 checks passed
@mrlubos mrlubos deleted the copilot/support-strict-unknown-typing branch March 3, 2026 01:48
@dosubot dosubot bot added the bug 🔥 Broken or incorrect behavior. label Mar 3, 2026
@hey-api hey-api bot mentioned this pull request Mar 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug 🔥 Broken or incorrect behavior. size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Generated BodySerializer uses any; please support strict unknown typing (or config option)

2 participants